﻿using System;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using NCMIS.ObjectModel;
using NCMIS.ObjectModel.Rest;
using NCMIS.ServiceModel.Syndication;
using System.ServiceModel.Syndication;
using NCMIS.Provider;

namespace NCMIS.ServiceModel.Ra
{
    /// <summary>
    /// Provides the Policy Services for the REST/Atom binding. The policy services are used to apply or remove a policy object
    /// to a controllable object.
    /// </summary>
    public partial class Service : IService
    {
        /// <summary>
        /// Applies a specified policy to an object.
        /// </summary>
        /// <param name="repositoryId">The id of the repository.</param>
        /// <param name="policyId">The id of the policy, to be applied.</param>
        /// <param name="objectId">The id of the object, on which to apply the policy.</param>
        [WebInvoke(Method = "POST", UriTemplate = "/{repositoryId}/object/{objectId}/policies/{policyId}")]
        public void ApplyPolicy(string repositoryId, string policyId, string objectId)
        {
            OutgoingWebResponseContext ctx = WebOperationContext.Current.OutgoingResponse;
            ctx.ContentType = CmisContentType.Feed;

            // Repository ID, object ID and policy ID must be specified
            if (String.IsNullOrEmpty(repositoryId) || String.IsNullOrEmpty(policyId) || String.IsNullOrEmpty(objectId))
            {
                ctx.StatusCode = ServiceException.InvalidArgument;
                ctx.StatusDescription = String.Format("{0}: The parameters repositoryId, policyId and objectId must not be null or empty.",
                    ServiceException.InvalidArgument.ToString());
                return;
            }

            // Apply the specified policy
            PolicyProviderManager.Provider.ApplyPolicy(repositoryId, policyId, objectId);
        }

        /// <summary>
        /// Removes a specified policy from an object.
        /// </summary>
        /// <param name="repositoryId">The id of the repository.</param>
        /// <param name="policyId">The id of the policy.</param>
        /// <param name="objectId">The id of the object.</param>
        [WebInvoke(Method = "DELETE", UriTemplate = "/{repositoryId}/object/{objectId}/policy/{policyId}")]
        public void RemovePolicy(string repositoryId, string policyId, string objectId)
        {
            OutgoingWebResponseContext ctx = WebOperationContext.Current.OutgoingResponse;
            ctx.ContentType = CmisContentType.Feed;

            // Repository ID, object ID and policy ID must be specified
            if (String.IsNullOrEmpty(repositoryId) || String.IsNullOrEmpty(policyId) || String.IsNullOrEmpty(objectId))
            {
                ctx.StatusCode = ServiceException.InvalidArgument;
                ctx.StatusDescription = String.Format("{0}: The parameters repositoryId, policyId and objectId must not be null or empty.",
                    ServiceException.InvalidArgument.ToString());
                return;
            }

            // Remove the specified policy
            PolicyProviderManager.Provider.RemovePolicy(repositoryId, policyId, objectId);
        }

        /// <summary>
        /// Gets the list of policies currently applied to the specified object.
        /// </summary>
        /// <param name="repositoryId">The id of the repository.</param>
        /// <param name="objectId">The id of the object.</param>
        /// <param name="filter">Value indicating which properties for Objects that must be returned. (Optional, default: Not set)</param>
        /// <returns>List of policies, formatted as Atom 1.0 Feed.</returns>
        [WebGet(UriTemplate = "/{repositoryId}/object/{objectId}/policies")]
        public Atom10FeedFormatter GetAppliedPolicies(string repositoryId, string objectId)
        {
            string filter = RequestParameter.Filter;

            OutgoingWebResponseContext ctx = WebOperationContext.Current.OutgoingResponse;
            ctx.ContentType = CmisContentType.Feed;

            // Repository ID must be specified
            if (String.IsNullOrEmpty(repositoryId))
            {
                ctx.StatusCode = ServiceException.InvalidArgument;
                ctx.StatusDescription = String.Format("{0}: The parameters repositoryId and folderId must not be null or empty.",
                    ServiceException.InvalidArgument.ToString());
                return null;
            }

            // Get the currently applied policies 
            CmisObjects cmisObjects = PolicyProviderManager.Provider.GetAppliedPolicies(repositoryId, objectId, filter);

            // Store the applied policies in a feed
            CmisSyndicationFeed feed = new CmisSyndicationFeed()
            {
                BaseUri = _baseUri,
                Id = "urn:uuid:policy-objects",
                RepositoryId = repositoryId,
                SelfLinkUri = new Uri(_baseUri, String.Format("{0}/typechildren", repositoryId)),
                ServiceLinkUri = new Uri(_baseUri, String.Format("{0}/servicedoc", repositoryId)),
                Title = new TextSyndicationContent("Base Types"),
            };
            feed.AddEntries(cmisObjects);
            feed.AddNumItems();

            // Format feed as an Atom feed
            return new Atom10FeedFormatter(feed);
        }
    }
}
